#include "recordthread.h"
#include <QMessageBox>
#include <pitchShift.h>

RecordThread::RecordThread(QWidget *parent)
{
    m_type = TOMCAT;
    m_playType = REALTIME;
    m_isplay = false;
    m_RecordEnable = false;
}

void RecordThread::pitchShift(short *input, short *output, int totalsize, int sampleRate, Types type, float PitchShift)
{
    if(!input && !output) return;
    float semitones;                            // 向上移动8个半音
    float pitchShift;    //将半音转换为因子

    std::vector<float> in(totalsize, 0);
    std::vector<float> out(totalsize, 0);
    for(int i=0; i<totalsize; i++)
    {
        in[i] = input[i]/32767.0;
    }
    switch (type) {
    case TOMCAT:
        semitones = 8;
        pitchShift = pow(2.0f, semitones / 12.0f);    //将半音转换为因子
        break;
    case MINIONS:
        pitchShift = 0.9;
        break;
    default:
        pitchShift = PitchShift;
    }
    smbPitchShift(pitchShift, totalsize, 2048, 4, sampleRate, in.data(), out.data());
    for(int i=0; i<totalsize; i++)
    {
        output[i] = (short)(out[i]*32767.0);
    }
}

int RecordThread::record(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, double streamTime, RtAudioStreamStatus status, void *userData)
{
    short* output = static_cast<short*>(outputBuffer);
    short* input = static_cast<short*>(inputBuffer);
    RecordThread *rd = (RecordThread *)userData;
    switch (rd->GetPlayType()) {

    case RECORD:
        if(!rd->m_RecordEnable)
        {
            memset(output, 0, nBufferFrames*sizeof(short));
            break;
        }
        if(!rd->m_isplay)
        {
            if(rd->m_RecordData.size() < 44100*5)
            {
                for(int i=0; i<nBufferFrames; i++)
                    rd->m_RecordData.push_back( input[i]);
            }
            else
            {
                rd->m_RecordEnable = false;
                rd->m_isplay = true;
                emit rd->recordOver();
            }
        }
        else
        {
            std::vector<short> pData(nBufferFrames, 0);
            if(rd->m_recordPlayIndex+nBufferFrames < rd->m_RecordData.size())
            {
                std::copy(rd->m_RecordData.begin()+rd->m_recordPlayIndex, rd->m_RecordData.begin()+rd->m_recordPlayIndex+nBufferFrames, pData.begin());
                rd->m_recordPlayIndex += nBufferFrames;
                pitchShift(pData.data(), output, nBufferFrames, 44100, rd->GetType(), rd->GetPitchShift());
            }
            else
            {
                rd->m_RecordEnable = false;
                rd->m_isplay = false;
                rd->m_recordPlayIndex = 0;
                rd->m_RecordData.clear();
                emit rd->recordPlayOver();
                memset(output, 0, nBufferFrames*sizeof(short));
            }
        }
        break;

    case REALTIME:
        pitchShift(input, output, nBufferFrames, 44100, rd->GetType(), rd->GetPitchShift());
        break;

    }

//    for (int i = 0; i < nBufferFrames; i += 1)
//    {
//        output[i] = input[i];
//    }
    return 0;
}

void RecordThread::run()
{
    if (adc.getDeviceCount() < 1) {
        exit( 0 );
    }

    //adc_.getDefaultInputDevice();获得默认输入设备
    input.deviceId = adc.getDefaultInputDevice();
    input.nChannels = 1;
    input.firstChannel = 0;

    output.deviceId = adc.getDefaultOutputDevice();
    output.nChannels = 1;
    output.firstChannel = 0;

    unsigned int sampleRate = 44100;
    unsigned int bufferFrames = 256;
    if (adc.isStreamRunning())adc.stopStream();
    if (adc.isStreamOpen())adc.closeStream();
    try {
        adc.openStream(&output, &input, RTAUDIO_SINT16, sampleRate,
                       &bufferFrames, &record, this);
        adc.startStream();
    }
    catch (RtAudioError& e) {
        stop();
        e.printMessage();
        exit(0);
    }

}

void RecordThread::stop()
{
    if (adc.isStreamRunning())adc.stopStream();
    if (adc.isStreamOpen())adc.closeStream();
}


void RecordThread::recordEnable()
{
    m_recordPlayIndex = 0;
    m_RecordData.clear();
    m_isplay = false;
    m_RecordEnable = true;
}

void RecordThread::recordEnablePlay()
{
    m_isplay = true;
    m_RecordEnable = true;
}
